//--------------------------------------------------------------------------
// 
//  Copyright (c) Christian Liensberger.  All rights reserved. 
// 
//  Licensed under GPL v2. See official license for details.
// 
//--------------------------------------------------------------------------

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;

namespace Chili.Imagizer
{
	/// <summary>
	/// Processes the images.
	/// </summary>
	public sealed class ImagesProcessor
	{
		/// <summary>
		/// Fired if an image is processed.
		/// </summary>
		public event EventHandler<ImageProcessingEventArgs> ImageProcessing;

		private void OnImageProcessing(ImageProcessingEventArgs e)
		{
			if (ImageProcessing != null)
				ImageProcessing(this, e);
		}

		/// <summary>
		/// Procresses the given images.
		/// </summary>
		/// <param name="outputDirectory">The output directory.</param>
		/// <param name="scaleFactor">The scale factor.</param>
		/// <param name="images">The list of images that is processed.</param>
		public void ProcessImages(string outputDirectory, float scaleFactor, ImagesCollection images)
		{
			if (outputDirectory == null)
				throw new ArgumentNullException("outputDirectory");
			if (images == null)
				throw new ArgumentNullException("images");

			DirectoryInfo output = new DirectoryInfo(outputDirectory);
			// Create the directory if not present.
			output.Create();

			// process all files.
			for(int i = 0; i < images.Count; i++)
			{
				FileInfo file = images[i];
				OnImageProcessing(new ImageProcessingEventArgs(file, i, images.Count));
				ProcessImage(file, output, scaleFactor, images.RootDirectory);
			}
		}

		/// <summary>
		/// Processes one file.
		/// </summary>
		/// <param name="file"></param>
		/// <param name="output"></param>
		/// <param name="scaleFactor"></param>
		private void ProcessImage(FileInfo file, DirectoryInfo output, float scaleFactor, DirectoryInfo root)
		{
			if (file == null)
				throw new ArgumentNullException("file");
			if (output == null)
				throw new ArgumentNullException("output");
			if (root == null)
				throw new ArgumentNullException("root");

			MemoryStream stream = null;
			// Get the image from the file.
			using (Image image = Image.FromFile(file.FullName))
			{
				int destWidth = (int)Math.Round(image.Width * scaleFactor);
				int destHeight = (int)Math.Round(image.Height * scaleFactor);

				// Create a new image that holds the result.
				using (Bitmap result = new Bitmap(destWidth, destHeight, image.PixelFormat))
				{
					// Set the resolution.
					result.SetResolution(image.HorizontalResolution, image.VerticalResolution);

					// Create a graphics object to create the new image.
					using (Graphics g = Graphics.FromImage(result))
					{
						// Set the interpolation mode to high quality.
						g.SmoothingMode = SmoothingMode.AntiAlias;
						g.InterpolationMode = InterpolationMode.HighQualityBicubic;
						g.PixelOffsetMode = PixelOffsetMode.HighQuality;
						// Draw the new image (resize).
						g.DrawImage(image, new Rectangle(0, 0, destWidth, destHeight), new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel);
					}

					// Create the memory stream and save the image to the stream.
					stream = new MemoryStream();
					result.Save(stream, image.RawFormat);
				}
			}

			// Return if the stream is null.
			if (stream == null)
				return;

			// Save the image.
			string path = output.FullName + @"\" + file.FullName.Replace(root.FullName, "");
			// TODO: Improve.
			if (File.Exists(path))
				File.Delete(path);
			// Create the directory to make sure it exists!
			Directory.CreateDirectory(Path.GetDirectoryName(path));

			// Write the stream to the file.
			File.WriteAllBytes(path, stream.ToArray());

			// Dispose the stream.
			stream.Dispose();
		}
	}
}
